﻿//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.UI;
using System.Linq.Expressions;
using System.Web.Script.Serialization;
using System.IO;

namespace DNA.Mvc.jQuery
{
    public abstract class ListBoxBuilder<TModel, TBuilder> : DataListBuilder<TModel, ListBox<TModel>, ListBoxOptions, TBuilder>
        where TModel : class
        where TBuilder : ListBoxBuilder<TModel, TBuilder>
    {
        protected override string jQueryPluginName
        {
            get { return "listbox"; }
        }

        public ListBoxBuilder(ListBox<TModel> listbox, ViewContext viewContext, IViewDataContainer viewContainer) :
            base(listbox, viewContext, viewContainer) { }

        /// <summary>
        /// Specified the target dropable html element id and allows ListBox drag items and drop on it.
        /// </summary>
        /// <param name="selector"></param>
        /// <returns></returns>
        public TBuilder ConnectTo(string selector)
        {
            Options(opts =>
            {
                opts.IsDroppable = true;
                opts.DropTargets = (((!selector.StartsWith(".")) && (!selector.StartsWith("#"))) ? "#" + selector : selector) + ">.d-list-items-holder";
            });
            return this as TBuilder;
        }

        /// <summary>
        /// Set the selected value
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public TBuilder Select(string value)
        {
            Component.Value = value;
            return this as TBuilder;
        }

        /// <summary>
        /// Set selected values.
        /// </summary>
        /// <param name="values"></param>
        /// <returns></returns>
        public TBuilder Select(string[] values)
        {
            Component.Value = string.Join(",", values);
            return this as TBuilder;
        }

        /// <summary>
        /// Show checkbox before every list item.
        /// </summary>
        /// <returns></returns>
        public TBuilder ShowCheckbox()
        {
            Options(opts =>
            {
                opts.ShowCheckbox = true;
            });
            return this as TBuilder;
        }

        protected string GenerateStartloadScripts()
        {
            var startHandler = new StringBuilder();
            startHandler.Append(jQuerySelector)
            .Append(".listbox(\"loadJson\",\"")
            .Append(Component.RemoteDataSource)
            .Append("\",{index:"+_index.ToString()+",size:"+_size.ToString()+"},\"")
            .Append(Component.Id).Append("_tmpl\",function(e,data){")
            .Append(jQuerySelector)
            .Append(".data(\"routeValues\",{index:" + _index.ToString() + ",size:" + _size.ToString() + ",count:data.Total,total:(Math.round(data.Total/" + _size.ToString() + ")+ (data.Total%" + _size.ToString() + " ? 1:0)) });")
            .Append("},\"")
            .Append(Component.HttpMethod)
            .Append("\");");
            return startHandler.ToString();
        }

        protected string GeneratePartialLoadScripts()
        {
            var scrollHandler = new StringBuilder();
            scrollHandler.Append("var _routeValues=")
                .Append(jQuerySelector)
                 .Append(".data(\"routeValues\");_routeValues.index++; if (_routeValues.total >= _routeValues.index) ")
                 .Append(jQuerySelector)
            .Append(".listbox(\"loadJson\",\"")
            .Append(Component.RemoteDataSource)
            .Append("\",_routeValues,\"")
            .Append(Component.Id).Append("_tmpl\",function(e,data){")
             .Append(jQuerySelector)
            .Append(".data(\"routeValues\",_routeValues);")
             .Append("},\"")
            .Append(Component.HttpMethod)
            .Append("\");");
            return scrollHandler.ToString();
        }

        private int _index = 1;
        private int _size = 20;
        private bool _pageable = true;

        public TBuilder Pagable(bool? allowPaging=true,int? pageIndex=1, int? pageSize=20)
        {
            _pageable = allowPaging.Value;
            _index=pageIndex.Value;
            _size = pageSize.Value;
            return this as TBuilder;
        }

        public TBuilder ItemHtmlAttributes(object htmlAttributes)
        {
            if (htmlAttributes != null)
                Component.ItemHtmlAttributes = ObjectHelper.ConvertObjectToDictionary(htmlAttributes);
            return this as TBuilder;
        }

        protected override void OnJsonDataBind(string jsonData, HtmlTextWriter writer)
        {
            Helper.RegisterStartupScript(jQuerySelector + ".listbox(\"dataBind\",eval(" + jsonData + "),\"" + this.Component.Id + "_tmpl\");");
        }

        protected override void OnRemoteDataBind(HtmlTextWriter writer)
        {
            //string loadOnScrollHandler = GeneratePartialLoadScripts();

            //Partical load
            Options(opts =>
            {
                if (_pageable)
                opts.OnScrollToEnd += GeneratePartialLoadScripts();
            });

            //base.Render();
            RenderComponent(writer);

            //First load
            Helper.RegisterStartupScript(GenerateStartloadScripts());
        }

    }

    public class ListBoxBuilder<TModel> : ListBoxBuilder<TModel, ListBoxBuilder<TModel>>
        where TModel : class
    {
        public ListBoxBuilder(ListBox<TModel> listbox, ViewContext viewContext, IViewDataContainer viewContainer) :
            base(listbox, viewContext, viewContainer) { }
    }

    public class ListBoxBuilder : ListBoxBuilder<INavigable, ListBoxBuilder>
    {
        public ListBoxBuilder(ListBox<INavigable> listbox, ViewContext viewContext, IViewDataContainer viewContainer) :
            base(listbox, viewContext, viewContainer) { }

        /// <summary>
        /// Bind string array to Combo
        /// </summary>
        /// <param name="values"></param>
        /// <returns></returns>
        public ListBoxBuilder Bind(string[] values)
        {
            var _list = new List<NavigableData>();
            for (int i = 0; i < values.Length; i++)
            {
                Component.AddItem(new NavigableView(new NavigableData()
                {
                    Title = values[i],
                    Value = values[i]
                }));
                //_list.Add();
            }
            //return Bind(_list) as ListBoxBuilder;
            return this;
        }
    }
}
